
`include "defines.v"

//----------------------------------------------------------------
//Module Name : if_stage.v
//Description of module:
//instration fetch 
//----------------------------------------------------------------
//Designer:	Tang Pengyu
//Date: 2021/07/13/20:41	  
//----------------------------------------------------------------

module	if_stage(
	input	clk,
	input	rst,							//high work
	input	[`REG_DATA_LEN-1:0] exe_data,	//use when jalr,branch
//when ecall	
	input	ecall_en,
	input	mret_en,
	input	[63:0]	mtvec,
	input	[63:0]	mepc,
	
	input	if_addr_ctrl,
	
	input	MTIP,			//计时器中断
	output	time_intr_r,		//高相应中断
	
	input	pc_sel,
  
	output	reg [`INST_ADDR_LEN-1:0] if_addr,		//指令寄存器地址
//	output	reg [`INST_ADDR_LEN-1:0] pc_add,
	output	inst_ena,
	output	reg	[`INST_LEN-1:0]	inst,
	
	output	reg [`INST_ADDR_LEN-1:0] pc_out,

	output	if_valid,
	input	if_ready,
	input	[63:0]	inst_data_read,
	output	[1:0]	if_size,
	input	[1:0]	if_resp,
	output	if_req,
	
	output	reg	fetched
		);
		
//reg	[`INST_ADDR_LEN-1 : 0]	pc;
wire	handshake_done;
assign	handshake_done = if_valid & if_ready;

reg [`INST_ADDR_LEN-1:0] pc_add;

always @(negedge clk)			//同步复位
  begin
	if(rst)
		pc_add <= 0;
	else
		pc_add <= if_addr + 4;
  end
wire	[`INST_ADDR_LEN-1:0]	pc_next;
assign	pc_next = (pc_sel == 1'b0) ? pc_add : 
					(ecall_en | time_intr_r) ? {mtvec[63:2],2'b00} :			//异常、中断时跳转到入口地址
					mret_en ? {mepc[63:2],2'b00} :
					{exe_data[`INST_ADDR_LEN-1:2],2'b00} ;
/*
reg		[`INST_ADDR_LEN-1:0]	pc_next_r1;
reg		[`INST_ADDR_LEN-1:0]	pc_next_r2;
always @(posedge clk)	begin
	pc_next_r1 <= pc_next;
	pc_next_r2 <= pc_next_r1;

end
*/					
reg		inst_useful;		//用于处理中断的指令作废信号，低 指令作废
assign	time_intr_r = ~inst_useful;

always @(posedge clk)
  begin
	if(rst)	begin
//		if_addr <= `PC_START;
		pc_out <= `PC_START;
		fetched <= 1'b0;
	end
	else if(handshake_done)	begin
//		if_addr <= pc_next;
		pc_out <= inst_useful ? if_addr : pc_out;
		fetched <= 1'b1;
		inst <= inst_useful ? inst_data_read[31:0] : inst;
	end
	else	begin
		fetched <= 1'b0;
	end
  end
  
//if_addr
always @(posedge clk)
  begin
	if(rst)
		if_addr <= `PC_START;
	else if(fetched)
		if_addr <= if_addr_ctrl ? pc_next : if_addr;
	else
		if_addr <= if_addr;
  
  end
  
  
//inst_useful

always @(posedge handshake_done)	begin
	inst_useful = MTIP ? 1'b0 : 1'b1;
end

assign	inst_ena = (rst == 1'b1) ? 1'b0 : 1'b1;
assign	if_valid = 1'b1;
assign	if_size = `SIZE_W;
assign	if_req = `REQ_READ;

endmodule